package com.sny.util;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import sun.misc.Cleaner;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.*;
import java.lang.reflect.Method;
import java.math.BigInteger;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.security.AccessController;
import java.security.MessageDigest;
import java.security.PrivilegedAction;

/**
 * @Author:yangxupeng
 * @Description:
 * @Date: 2020/7/30 4:36 下午
 * @Modified:
 */
@Slf4j
@Component
public class FileUtil {
    private static String imgSufStr;
    private static String docSufStr;
    private static String srcSufStr;
    private static String audioSufStr;
    private static String videoSufStr;
    private static String zipSufStr;
    private static String denySufStr;
    private static String imgWidth;
    private static String imgHeight;
    private static String imgMediumWidth;
    private static String imgMediumHeight;
    private static String imgSmallWidth;
    private static String imgSmallHeight;

    public static final String DOT = ".";


    /**
     * 计算文件夹大小
     *
     * @param directory
     * @return
     */
    public static Long calDirSize(String directory) {
        Long size = 0L;
        File f = new File(directory);
        File[] subf = f.listFiles();
        for (int i = 0; i < subf.length; i++) {
            if (subf[i].isDirectory()) {
                size += calDirSize(subf[i].toString());
            } else {
                size += subf[i].length();
            }
        }
        return size;
    }

    /**
     * 获取文件类型
     *
     * @param filename
     * @return
     */
    public static String getFileType(String filename) {
        String type = "other";
        if (filename == null || filename.trim().length() == 0) {
            return type;
        }
        String fSuf = getFileSuffix(filename);

        String imgSuf = imgSufStr;
        String docSuf = docSufStr;
        String srcSuf = srcSufStr;
        String audioSuf = audioSufStr;
        String videoSuf = videoSufStr;
        String zipSuf = zipSufStr;
        //String otherSuf = Play.configuration.getProperty("attachments.suf.other", ".7z;.iso;.torrent;");

        if (imgSuf.indexOf(fSuf) >= 0) {
            type = "img";
        } else if (docSuf.indexOf(fSuf) >= 0) {
            type = "doc";
        } else if (srcSuf.indexOf(fSuf) >= 0) {
            type = "src";
        } else if (audioSuf.indexOf(fSuf) >= 0) {
            type = "audio";
        } else if (videoSuf.indexOf(fSuf) >= 0) {
            type = "video";
        } else if (zipSuf.indexOf(fSuf) >= 0) {
            type = "zip";
        } else {
            type = "other";
        }

        return type;
    }

    public static Boolean isFileDenied(String filename) {
        Boolean fd = false;
        if (filename == null || filename.trim().length() == 0) {
            return fd;
        }

        String denySuf = denySufStr;
        String fSuf = getFileSuffix(filename);

        if (denySuf.indexOf(fSuf) >= 0) {
            fd = true;
        }

        return fd;
    }

    public static String getFileName(String filepath) {
        String filename = "";
        if (filepath != null && filepath.trim().length() > 0) {
            File file = new File(filepath);
            if (file.exists()) {
                filename = file.getName();
            }
        }

        return filename;
    }

    public static String getFileSuffix(String filename) {
        String suf = "";
        if (filename != null && filename.trim().length() > 0) {
            int lio = filename.lastIndexOf(".");
            if (lio >= 0) {
                suf = filename.substring(lio);
            }
        }
        suf = suf.toLowerCase();
        return suf;
    }

    public static String getFilePureName(String filename) {
        String pn = filename;
        if (filename != null && filename.lastIndexOf(".") >= 0) {
            pn = filename.substring(0, filename.lastIndexOf("."));
        }

        return pn;
    }

    /**
     * ut = "s" 为snapshot缩略图， = "c" 为compress压缩
     */
    public static String getFileNameByUst(String filename, String ust) {
        String un = filename;
        if (filename != null && filename.trim().length() > 0 && ust != null) {
            String suf = getFileSuffix(filename);
            un = getFilePureName(filename) + "_" + ust + suf;
        }

        return un;
    }

    public static String getFileNameBySuffix(String filename, String suf) {
        String sn = filename;
        if (filename != null && filename.trim().length() > 0 && suf != null) {
            sn = getFilePureName(filename) + suf;
        }

        return sn;
    }

    public static void isExist(String path) {
        File file = new File(path);
        if (!file.exists() && !file.isDirectory()) {
            log.info("文件不存在");
            file.mkdirs();
        } else {
            log.info("目录存在");
        }
    }

    public static String getMd5ByFile(File file) {
        String value = null;
        FileInputStream in = null;
        try {
            in = new FileInputStream(file);
            MappedByteBuffer byteBuffer = in.getChannel().map(FileChannel.MapMode.READ_ONLY, 0, file.length());
            MessageDigest md5 = MessageDigest.getInstance("MD5");
            md5.update(byteBuffer);
            BigInteger bi = new BigInteger(1, md5.digest());
            value = bi.toString(16);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (null != in) {
                try {
                    in.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return value;
    }

    public static void imagesResize(File file, String dir) {
        String fileUuidName = file.getName();
        String uuid = file.getName().substring(0, file.getName().indexOf("."));
        String fileSuf = FileUtil.getFileSuffix(file.getName());
        String fileDifUseName = "";
        try {
            if (fileSuf != null && (fileSuf.equalsIgnoreCase(".jpeg") || fileSuf.equalsIgnoreCase(".jpg") || fileSuf.equalsIgnoreCase(".gif") || fileSuf.equalsIgnoreCase(".png") || fileSuf.equalsIgnoreCase(".bmp"))) {
                BufferedImage sourceImg = ImageIO.read(new FileInputStream(file));
                fileDifUseName = uuid + "_w" + fileSuf;
                File tos = new File(dir + fileDifUseName);
                Image img = ImageIO.read(file);
                BufferedImage tmpFileImg = null;
                // Files.copy(file, tos);
                FileUtils.copyFile(file, tos);
                // WaterMark.pressImage("../fms/conf/watermark/large.png", dir + fileDifUseName, 0, 0);

                if (sourceImg.getWidth() > 1280 || sourceImg.getHeight() > 800) {
                    fileDifUseName = uuid + "_c" + fileSuf;
                    tos = new File(dir + fileDifUseName);
                    tmpFileImg = resizeImage(img, Integer.parseInt(imgWidth), Integer.parseInt(imgHeight));
                    ImageIO.write(tmpFileImg, fileSuf.replace(".", ""), tos);
                    //WaterMark.pressImage("../fms/conf/watermark/large.png", dir + fileDifUseName, 0, 0);
                }
                if (sourceImg.getWidth() > 800 || sourceImg.getHeight() > 600) {
                    fileDifUseName = uuid + "_m" + fileSuf;
                    tos = new File(dir + fileDifUseName);
                    tmpFileImg = resizeImage(img, Integer.parseInt(imgMediumWidth), Integer.parseInt(imgMediumHeight));
                    ImageIO.write(tmpFileImg, fileSuf.replace(".", ""), tos);
                    // WaterMark.pressImage("../fms/conf/watermark/normal.png", dir + fileDifUseName, 0, 0);
                }
                if (sourceImg.getWidth() > 320 || sourceImg.getHeight() > 240) {
                    fileDifUseName = uuid + "_s" + fileSuf;
                    tos = new File(dir + fileDifUseName);
                    tmpFileImg = resizeImage(img, Integer.parseInt(imgSmallWidth), Integer.parseInt(imgSmallHeight));
                    ImageIO.write(tmpFileImg, fileSuf.replace(".", ""), tos);
                    // WaterMark.pressImage("../fms/conf/watermark/small.png", dir + fileDifUseName, 0, 0);
                }

            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static BufferedImage resizeImage(final Image image, int width, int height) {
        final BufferedImage bufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        final Graphics2D graphics2D = bufferedImage.createGraphics();
        graphics2D.setComposite(AlphaComposite.Src);
        //below three lines are for RenderingHints for better image quality at cost of higher processing time
        graphics2D.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
        graphics2D.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
        graphics2D.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        graphics2D.drawImage(image, 0, 0, width, height, null);
        graphics2D.dispose();
        return bufferedImage;
    }

//    public static void imagesResizeWaterMark(File file,String dir){
//        String fileUuidName = file.getName();
//        String uuid=file.getName().substring(0,file.getName().indexOf("."));
//        String fileSuf = FileUtil.getFileSuffix(file.getName());
//        String fileDifUseName = "";
//        try {
//            if (fileSuf != null && (fileSuf.equalsIgnoreCase(".jpeg") ||fileSuf.equalsIgnoreCase(".jpg") || fileSuf.equalsIgnoreCase(".gif") || fileSuf.equalsIgnoreCase(".png") || fileSuf.equalsIgnoreCase(".bmp"))) {
//                BufferedImage sourceImg =ImageIO.read(new FileInputStream(file));
//                fileDifUseName = uuid + "_w" + fileSuf;
//                File tos = new File(dir + fileDifUseName);
////                Files.copy(file, tos);
//                FileUtils.copyFile(file,tos);
//                WaterMark.pressImage("../fms/conf/watermark/large.png", dir + fileDifUseName, 0, 0);
//
//                if(sourceImg.getWidth()>1280||sourceImg.getHeight()>800) {
//                    fileDifUseName = uuid + "_c" + fileSuf;
//                    tos = new File(dir + fileDifUseName);
//                    Images.resize(file, tos, Integer.parseInt(Play.configuration.getProperty("application.IMAGES.COMPRESSION.W", "1280")), Integer.parseInt(Play.configuration.getProperty("application.IMAGES.COMPRESSION.H", "800")), true);
//                    WaterMark.pressImage("../fms/conf/watermark/large.png", dir + fileDifUseName, 0, 0);
//                }
//                if(sourceImg.getWidth()>800||sourceImg.getHeight()>600) {
//                    fileDifUseName = uuid + "_m" + fileSuf;
//                    tos = new File(dir + fileDifUseName);
//                    Images.resize(file, tos, Integer.parseInt(Play.configuration.getProperty("application.IMAGES.MEDIUM.W", "800")), Integer.parseInt(Play.configuration.getProperty("application.IMAGES.MEDIUM.H", "600")), true);
//                    WaterMark.pressImage("../fms/conf/watermark/normal.png", dir + fileDifUseName, 0, 0);
//                }
//                if(sourceImg.getWidth()>320||sourceImg.getHeight()>240) {
//                    fileDifUseName = uuid + "_s" + fileSuf;
//                    tos = new File(dir + fileDifUseName);
//                    Images.resize(file, tos, Integer.parseInt(Play.configuration.getProperty("application.IMAGES.SMALL.W", "320")), Integer.parseInt(Play.configuration.getProperty("application.IMAGES.SMALL.H", "240")), true);
//                    WaterMark.pressImage("../fms/conf/watermark/small.png", dir + fileDifUseName, 0, 0);
//                }
//
//            }
//        }catch (Exception e){
//            e.printStackTrace();
//        }
//    }

    /**
     * 删除单个文件
     *
     * @param filedir 被删除文件的文件名
     * @return 单个文件删除成功返回true，否则返回false
     */
    public static boolean deleteFile(File filedir) {

        // 路径为文件且不为空则进行删除
        if (filedir.isFile() && filedir.exists()) {
            filedir.delete();
            return true;
        }
        return false;
    }

    /**
     * 删除目录（文件夹）以及目录下的文件
     *
     * @param dirFile 被删除目录的文件路径
     * @return 目录删除成功返回true，否则返回false
     */
    public static boolean deleteDirectory(File dirFile) {

        //如果dir对应的文件不存在，或者不是一个目录，则退出
        if (!dirFile.exists() || !dirFile.isDirectory()) {
            return false;
        }
        boolean flag = true;
        //删除文件夹下的所有文件(包括子目录)
        File[] files = dirFile.listFiles();
        for (int i = 0; i < files.length; i++) {
            //删除子文件
            if (files[i].isFile()) {
                flag = deleteFile(files[i]);
                if (!flag) break;
            } //删除子目录
            else {
                flag = deleteDirectory(files[i]);
                if (!flag) break;
            }
        }
        if (!flag) return false;
        //删除当前目录
        if (dirFile.delete()) {
            return true;
        } else {
            return false;
        }
    }

    /**
     * 复制单个文件
     *
     * @param oldPath
     * @return newPath，
     */
    public static void copyFile(String oldPath, String newPath) {
        try {
            int bytesum = 0;
            int byteread = 0;
            File oldfile = new File(oldPath);
            if (oldfile.exists()) { //文件存在时
                InputStream inStream = new FileInputStream(oldPath); //读入原文件
                FileOutputStream fs = new FileOutputStream(newPath);
                byte[] buffer = new byte[1444];
                int length;
                while ((byteread = inStream.read(buffer)) != -1) {
                    bytesum += byteread; //字节数 文件大小
                    System.out.println(bytesum);
                    fs.write(buffer, 0, byteread);
                }
                inStream.close();
            }
        } catch (Exception e) {
            //  System.out.println("复制单个文件操作出错");
            e.printStackTrace();
        }
    }

    /**
     * 获取扩展名
     */
    public static String getExtension(String fileName) {

        if (StringUtils.INDEX_NOT_FOUND == StringUtils.indexOf(fileName, DOT)) {
            return StringUtils.EMPTY;
        }
        String ext = StringUtils.substring(fileName,
                StringUtils.lastIndexOf(fileName, DOT) + 1);
        return StringUtils.trimToEmpty(ext);
    }

    public static void close(final Closeable closeable) {
        if (closeable != null) {
            try {
                closeable.close();
            } catch (IOException e) {
                log.error("close fail:" + e.getMessage(), e);
            } finally {
            }
        }
    }

    public static void close(FileInputStream in, MappedByteBuffer byteBuffer) {

        if (null != in) {
            try {
                in.getChannel().close();
                in.close();
            } catch (IOException e) {
                log.error("close error:" + e.getMessage(), e);
            }
        }
        if (null != byteBuffer) {
            freedMappedByteBuffer(byteBuffer);
        }
    }


    /**
     * 在MappedByteBuffer释放后再对它进行读操作的话就会引发jvm crash，在并发情况下很容易发生 正在释放时另一个线程正开始读取，于是crash就发生了。所以为了系统稳定性释放前一般需要检 查是否还有线程在读或写
     */
    public static void freedMappedByteBuffer(final MappedByteBuffer mappedByteBuffer) {

        try {
            if (mappedByteBuffer == null) {
                return;
            }

            mappedByteBuffer.force();
            AccessController.doPrivileged(new PrivilegedAction<Object>() {
                @Override
                public Object run() {

                    try {
                        Method getCleanerMethod = mappedByteBuffer.getClass().getMethod("cleaner", new Class[0]);
                        getCleanerMethod.setAccessible(true);
                        Cleaner cleaner = (Cleaner) getCleanerMethod.invoke(mappedByteBuffer,
                                new Object[0]);
                        cleaner.clean();
                    } catch (Exception e) {
                        log.error("clean MappedByteBuffer error!!!", e);
                    }
                    log.info("clean MappedByteBuffer completed!!!");
                    return null;
                }
            });

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Value("${fms.attachments.suf.img}")
    public void setImgSufStr(String imgSufStr) {
        FileUtil.imgSufStr = imgSufStr;
    }

    @Value("${fms.attachments.suf.doc}")
    public void setDocSufStr(String docSufStr) {
        FileUtil.docSufStr = docSufStr;
    }

    @Value("${fms.attachments.suf.src}")
    public void setSrcSufStr(String srcSufStr) {
        FileUtil.srcSufStr = srcSufStr;
    }

    @Value("${fms.attachments.suf.audio}")
    public void setAudioSufStr(String audioSufStr) {
        FileUtil.audioSufStr = audioSufStr;
    }

    @Value("${fms.attachments.suf.video}")
    public void setVideoSufStr(String videoSufStr) {
        FileUtil.videoSufStr = videoSufStr;
    }

    @Value("${fms.attachments.suf.zip}")
    public void setZipSufStr(String zipSufStr) {
        FileUtil.zipSufStr = zipSufStr;
    }

    @Value("${fms.attachments.suf.deny}")
    public void setDenySufStr(String denySufStr) {
        FileUtil.denySufStr = denySufStr;
    }

    @Value("${fms.application.IMAGES.COMPRESSION.W}")
    public void setImgWidth(String imgWidth) {
        FileUtil.imgWidth = imgWidth;
    }

    @Value("${fms.application.IMAGES.COMPRESSION.H}")
    public void setImgHeight(String imgHeight) {
        FileUtil.imgHeight = imgHeight;
    }

    @Value("${fms.application.IMAGES.MEDIUM.W}")
    public void setImgMediumWidth(String imgMediumWidth) {
        FileUtil.imgMediumWidth = imgMediumWidth;
    }

    @Value("${fms.application.IMAGES.MEDIUM.H}")
    public void setImgMediumHeight(String imgMediumHeight) {
        FileUtil.imgMediumHeight = imgMediumHeight;
    }

    @Value("${fms.application.IMAGES.SMALL.W}")
    public void setImgSmallWidth(String imgSmallWidth) {
        FileUtil.imgSmallWidth = imgSmallWidth;
    }

    @Value("${fms.application.IMAGES.SMALL.H}")
    public void setImgSmallHeight(String imgSmallHeight) {
        FileUtil.imgSmallHeight = imgSmallHeight;
    }
}
